import { merge } from 'lodash-es'
import { isFunction } from '@vue/shared'
import { HttpRequestOptions, RequestConfig, RequestOptions, UploadFileOption } from './type'
import { RequestErrMsgEnum, RequestMethodsEnum } from '@/enums/requestEnums'
import requestCancel from './cancel'

export default class HttpRequest {
    private readonly options: HttpRequestOptions
    constructor(options: HttpRequestOptions) {
        this.options = options
    }
    /**
     * @description 重新请求
     */
    retryRequest(options: RequestOptions, config: RequestConfig) {
        const { retryCount, retryTimeout } = config
        if (!retryCount || options.method?.toUpperCase() == RequestMethodsEnum.POST) {
            return Promise.reject()
        }
        uni.showLoading({ title: '加载中...' })
        config.hasRetryCount = config.hasRetryCount ?? 0
        if (config.hasRetryCount >= retryCount) {
            return Promise.reject()
        }
        config.hasRetryCount++
        config.requestHooks.requestInterceptorsHook = (options) => options
        return new Promise((resolve) => setTimeout(resolve, retryTimeout))
            .then(() => this.request(options, config))
            .finally(() => uni.hideLoading())
    }
    /**
     * @description get请求
     */
    get<T = any>(options: RequestOptions, config?: Partial<RequestConfig>): Promise<T> {
        return this.request({ ...options, method: RequestMethodsEnum.GET }, config)
    }

    /**
     * @description post请求
     */
    post<T = any>(options: RequestOptions, config?: Partial<RequestConfig>): Promise<T> {
        return this.request({ ...options, method: RequestMethodsEnum.POST }, config)
    }

    /**
     * @description 上传图片
     */
    uploadFile(options: UploadFileOption, config?: Partial<RequestConfig>) {
        let mergeOptions: RequestOptions = merge({}, this.options.requestOptions, options)
        const mergeConfig: RequestConfig = merge({}, this.options, config)
        const { requestInterceptorsHook, responseInterceptorsHook, responseInterceptorsCatchHook } =
            mergeConfig.requestHooks || {}
        if (requestInterceptorsHook && isFunction(requestInterceptorsHook)) {
            mergeOptions = requestInterceptorsHook(mergeOptions, mergeConfig)
        }
        return new Promise((resolve, reject) => {
            uni.uploadFile({
                ...mergeOptions,
                success: async (response) => {
                    if (response.statusCode == 200) {
                        response.data = JSON.parse(response.data)
                        if (responseInterceptorsHook && isFunction(responseInterceptorsHook)) {
                            try {
                                response = await responseInterceptorsHook(response, mergeConfig)
                                resolve(response)
                            } catch (error) {
                                reject(error)
                            }
                            return
                        }
                        resolve(response)
                    }
                },
                fail: async (err) => {
                    if (
                        responseInterceptorsCatchHook &&
                        isFunction(responseInterceptorsCatchHook)
                    ) {
                        reject(await responseInterceptorsCatchHook(mergeOptions, err))
                        return
                    }
                    reject(err)
                }
            })
        })
    }
    /**
     * @description 请求函数
     */
    async request(options: RequestOptions, config?: Partial<RequestConfig>): Promise<any> {
        let mergeOptions: RequestOptions = merge({}, this.options.requestOptions, options)
        const mergeConfig: RequestConfig = merge({}, this.options, config)
        const { requestInterceptorsHook, responseInterceptorsHook, responseInterceptorsCatchHook } =
            mergeConfig.requestHooks || {}
        if (requestInterceptorsHook && isFunction(requestInterceptorsHook)) {
            mergeOptions = requestInterceptorsHook(mergeOptions, mergeConfig)
        }
        return new Promise((resolve, reject) => {
            const requestTask = uni.request({
                ...mergeOptions,
                async success(response) {
                    // APP 平台下，检查响应对象
                    // #ifdef APP-PLUS
                    console.log('APP 平台请求成功，响应:', {
                        response,
                        hasData: !!response?.data,
                        dataType: typeof response?.data,
                        statusCode: response?.statusCode,
                        url: mergeOptions.url
                    })
                    
                    if (!response) {
                        console.error('APP 平台请求成功但响应为空')
                        reject(new Error('请求响应为空'))
                        return
                    }
                    
                    // 检查响应数据
                    if (!response.data) {
                        console.error('APP 平台响应数据为空:', { response, url: mergeOptions.url })
                        reject(new Error('响应数据为空'))
                        return
                    }
                    // #endif
                    
                    if (responseInterceptorsHook && isFunction(responseInterceptorsHook)) {
                        try {
                            const result = await responseInterceptorsHook(response, mergeConfig)
                            // APP 平台下，检查返回结果
                            // #ifdef APP-PLUS
                            if (result === null || result === undefined) {
                                console.error('APP 平台响应拦截器返回 null:', { response, result })
                                reject(new Error('接口返回数据为空'))
                                return
                            }
                            // #endif
                            resolve(result)
                        } catch (error) {
                            // APP 平台下，确保错误不是 null，并且总是返回 Error 对象
                            // #ifdef APP-PLUS
                            console.error('APP 平台响应拦截器抛出错误:', {
                                error,
                                errorType: typeof error,
                                errorIsNull: error === null,
                                errorIsUndefined: error === undefined,
                                errorIsObject: error && typeof error === 'object',
                                errorIsEmptyObject: error && typeof error === 'object' && Object.keys(error).length === 0,
                                errorMessage: error?.message,
                                errorMsg: error?.msg,
                                errorString: String(error),
                                response,
                                url: mergeOptions.url
                            })
                            
                            // 确保总是 reject 一个 Error 对象
                            if (error === null || error === undefined) {
                                console.error('APP 平台响应拦截器返回 null 错误')
                                reject(new Error('接口处理失败'))
                            } else if (error && typeof error === 'object' && Object.keys(error).length === 0) {
                                // 处理空对象错误
                                console.error('APP 平台响应拦截器返回空对象错误')
                                const responseData = response?.data as any
                                const errorMessage = responseData?.msg || 
                                                    (responseData?.code === 500 ? '服务器错误，请稍后重试' : '接口处理失败')
                                reject(new Error(errorMessage))
                            } else if (error instanceof Error) {
                                reject(error)
                            } else if (typeof error === 'string') {
                                reject(new Error(error))
                            } else {
                                // 其他类型的错误，转换为 Error
                                const errorMessage = error?.message || error?.msg || String(error) || '接口处理失败'
                                reject(new Error(errorMessage))
                            }
                            // #endif
                            // #ifndef APP-PLUS
                            // 非 APP 平台也要确保错误是 Error 对象
                            if (error instanceof Error) {
                            reject(error)
                            } else if (error === null || error === undefined) {
                                reject(new Error('接口处理失败'))
                            } else {
                                const errorMessage = error?.message || error?.msg || String(error) || '接口处理失败'
                                reject(new Error(errorMessage))
                            }
                            // #endif
                        }
                        return
                    }
                    resolve(response)
                },
                fail: async (err) => {
                    // APP 平台下，记录详细的错误信息
                    // #ifdef APP-PLUS
                    console.error('APP 平台请求失败:', {
                        err,
                        errMsg: err?.errMsg,
                        url: mergeOptions.url,
                        method: mergeOptions.method
                    })
                    // #endif
                    
                    if (err.errMsg == RequestErrMsgEnum.TIMEOUT) {
                        this.retryRequest(mergeOptions, mergeConfig)
                            .then((res) => resolve(res))
                            .catch((retryErr) => {
                                // 确保 reject 的不是 null
                                if (retryErr === null || retryErr === undefined) {
                                    reject(new Error('请求超时，重试失败'))
                                } else {
                                    reject(retryErr)
                                }
                            })
                        return
                    }

                    if (
                        responseInterceptorsCatchHook &&
                        isFunction(responseInterceptorsCatchHook)
                    ) {
                        const catchError = await responseInterceptorsCatchHook(mergeOptions, err)
                        // APP 平台下，确保错误不是 null
                        // #ifdef APP-PLUS
                        if (catchError === null || catchError === undefined) {
                            reject(new Error(err?.errMsg || '请求失败'))
                        } else {
                            reject(catchError)
                        }
                        // #endif
                        // #ifndef APP-PLUS
                        reject(catchError)
                        // #endif
                        return
                    }
                    // 确保 reject 的不是 null
                    if (err === null || err === undefined) {
                        reject(new Error('请求失败'))
                    } else {
                    reject(err)
                    }
                },
                complete(err) {
                    if (err.errMsg !== RequestErrMsgEnum.ABORT) {
                        requestCancel.remove(options.url)
                    }
                }
            })
            const { ignoreCancel } = mergeConfig
            !ignoreCancel && requestCancel.add(options.url, requestTask)
        })
    }
}
